﻿# 引入os模块，用于处理文件和目录
import os  # 导入操作系统接口模块，用于文件操作
import datetime  # 导入日期时间模块，用于生成时间戳
from typing import List, Tuple, Optional  # 导入类型注解，提高代码可读性

# 定义一个全局字典admins，用于存储管理员信息
admins = {}  # 创建空字典存储管理员用户名和密码

# 定义商品类型
Product = Tuple[str, str, int, int, int]  # 定义商品类型别名：(编号, 名称, 进价, 售价, 库存)

def print_header(title: str):  # 定义打印标题的函数，参数为标题字符串
    """打印美化的标题"""
    print("\n" + "="*60)  # 打印换行和60个等号作为上边框
    print(f"{'':^20}{title:^20}{'':^20}")  # 居中显示标题，左右各20个空格
    print("="*60)  # 打印60个等号作为下边框

def print_separator():  # 定义打印分隔线的函数
    """打印分隔线"""
    print("-" * 60)  # 打印60个短横线作为分隔线

def print_success(message: str):  # 定义打印成功信息的函数
    """打印成功信息"""
    print(f"✅ {message}")  # 在消息前添加绿色对勾表示成功

def print_error(message: str):  # 定义打印错误信息的函数
    """打印错误信息"""
    print(f"❌ {message}")  # 在消息前添加红色叉号表示错误

def print_warning(message: str):  # 定义打印警告信息的函数
    """打印警告信息"""
    print(f"⚠️  {message}")  # 在消息前添加黄色警告符号

def print_info(message: str):  # 定义打印提示信息的函数
    """打印信息"""
    print(f"ℹ️  {message}")  # 在消息前添加蓝色信息符号

# 定义函数，用于加载admins信息
def load_admins():  # 定义加载管理员信息的函数
    """加载管理员信息"""
    global admins  # 声明使用全局变量admins
    try:  # 使用异常处理确保程序稳定性
        if os.path.exists("admins.txt"):  # 检查管理员文件是否存在
            with open("admins.txt", "r", encoding="utf-8") as file:  # 以UTF-8编码打开文件
                for line_num, line in enumerate(file, 1):  # 遍历文件每一行，从1开始编号
                    line = line.strip()  # 去除行首尾的空白字符
                    if not line:  # 如果是空行则跳过
                        continue  # 继续下一次循环
                    try:  # 处理单行数据的异常
                        username, password = line.split(",", 1)  # 按逗号分割，最多分割1次
                        if username and password:  # 确保用户名和密码都不为空
                            admins[username] = password  # 将用户名和密码存入字典
                    except ValueError:  # 捕获分割失败的异常
                        print_warning(f"管理员文件第{line_num}行格式错误，已跳过")  # 提示格式错误
    except Exception as e:  # 捕获所有其他异常
        print_error(f"加载管理员信息失败: {e}")  # 显示错误信息

# 定义函数，用于保存admins信息
def save_admins():  # 定义保存管理员信息的函数
    """保存管理员信息"""
    try:  # 使用异常处理确保文件操作安全
        with open("admins.txt", "w", encoding="utf-8") as file:  # 以写入模式打开文件
            for username, password in admins.items():  # 遍历管理员字典的所有键值对
                file.write(f"{username},{password}\n")  # 将用户名和密码以逗号分隔写入文件
    except Exception as e:  # 捕获文件操作异常
        print_error(f"保存管理员信息失败: {e}")  # 显示保存失败的错误信息

def validate_username(username: str) -> bool:  # 定义验证用户名的函数，返回布尔值
    """验证用户名格式"""
    if not username:  # 检查用户名是否为空
        print_error("用户名不能为空")  # 显示错误信息
        return False  # 返回验证失败
    if len(username) < 3:  # 检查用户名长度是否小于3
        print_error("用户名长度不能少于3个字符")  # 显示长度不足错误
        return False  # 返回验证失败
    if len(username) > 20:  # 检查用户名长度是否超过20
        print_error("用户名长度不能超过20个字符")  # 显示长度超限错误
        return False  # 返回验证失败
    if not username.replace('_', '').replace('-', '').isalnum():  # 检查是否只包含字母数字下划线连字符
        print_error("用户名只能包含字母、数字、下划线和连字符")  # 显示字符格式错误
        return False  # 返回验证失败
    return True  # 所有验证通过，返回成功

def validate_password(password: str) -> bool:  # 定义验证密码的函数，返回布尔值
    """验证密码格式"""
    if not password:  # 检查密码是否为空
        print_error("密码不能为空")  # 显示密码为空错误
        return False  # 返回验证失败
    if len(password) < 6:  # 检查密码长度是否小于6
        print_error("密码长度不能少于6个字符")  # 显示密码长度不足错误
        return False  # 返回验证失败
    if len(password) > 50:  # 检查密码长度是否超过50
        print_error("密码长度不能超过50个字符")  # 显示密码长度超限错误
        return False  # 返回验证失败
    return True  # 所有验证通过，返回成功

# 定义函数，用于注册管理员
def register():  # 定义管理员注册函数
    """注册管理员"""
    print_header("管理员注册")  # 显示注册页面标题
    
    while True:  # 无限循环直到输入有效用户名
        username = input("请输入管理员用户名: ").strip()  # 获取用户输入并去除空白字符
        if not validate_username(username):  # 验证用户名格式
            continue  # 验证失败则重新输入
        if username in admins:  # 检查用户名是否已存在
            print_error("用户名已存在，请重新输入")  # 显示用户名重复错误
            continue  # 重新输入用户名
        break  # 用户名有效且不重复，跳出循环
    
    while True:  # 无限循环直到输入有效密码
        password = input("请输入管理员密码: ").strip()  # 获取密码输入
        if not validate_password(password):  # 验证密码格式
            continue  # 验证失败则重新输入
        confirm_password = input("请确认管理员密码: ").strip()  # 获取确认密码
        if password != confirm_password:  # 比较两次密码输入是否一致
            print_error("两次输入的密码不一致，请重新输入")  # 显示密码不一致错误
            continue  # 重新输入密码
        break  # 密码有效且一致，跳出循环
    
    admins[username] = password  # 将新管理员信息存入字典
    save_admins()  # 保存管理员信息到文件
    print_success("管理员注册成功！")  # 显示注册成功信息

# 定义函数，用于管理员登录
def login() -> bool:  # 定义登录函数，返回布尔值表示登录是否成功
    """管理员登录"""
    print_header("管理员登录")  # 显示登录页面标题
    
    max_attempts = 3  # 设置最大尝试次数为3次
    attempts = 0  # 初始化当前尝试次数为0
    
    while attempts < max_attempts:  # 当尝试次数未达到上限时循环
        username = input("请输入管理员用户名: ").strip()  # 获取用户名输入
        if username not in admins:  # 检查用户名是否存在于管理员字典中
            print_error("用户名不存在")  # 显示用户名不存在错误
            attempts += 1  # 增加尝试次数
            if attempts < max_attempts:  # 如果还有尝试机会
                print_info(f"还有 {max_attempts - attempts} 次尝试机会")  # 显示剩余尝试次数
            continue  # 继续下一次循环
        
        password = input("请输入管理员密码: ").strip()  # 获取密码输入
        if admins[username] == password:  # 验证密码是否正确
            print_success(f"欢迎您，{username}！登录成功")  # 显示登录成功信息
            return True  # 返回登录成功
        else:  # 密码错误的情况
            print_error("密码错误")  # 显示密码错误信息
            attempts += 1  # 增加尝试次数
            if attempts < max_attempts:  # 如果还有尝试机会
                print_info(f"还有 {max_attempts - attempts} 次尝试机会")  # 显示剩余尝试次数
    
    print_error("登录失败次数过多，请稍后再试")  # 显示尝试次数过多错误
    return False  # 返回登录失败

# 定义函数，通过csv格式的字符串创建商品对象
def from_csv(csv_line: str) -> Optional[Product]:  # 定义CSV解析函数，返回商品对象或None
    """从CSV行创建商品对象"""
    try:  # 使用异常处理确保解析安全
        parts = csv_line.strip().split(",")  # 去除空白字符并按逗号分割
        if len(parts) != 5:  # 检查分割后的部分数量是否为5
            return None  # 格式不正确则返回None
        bianhao, mingcheng, jinjia, shoujia, kucun = parts  # 解包分割后的各部分
        return (bianhao, mingcheng, int(jinjia), int(shoujia), int(kucun))  # 返回商品元组，价格和库存转为整数
    except (ValueError, IndexError):  # 捕获类型转换和索引错误
        return None  # 解析失败返回None

# 定义函数，将商品信息转换为csv格式的字符串
def to_csv(shangpin: Product) -> str:  # 定义商品对象转CSV字符串的函数
    """将商品对象转换为CSV格式"""
    return f"{shangpin[0]},{shangpin[1]},{shangpin[2]},{shangpin[3]},{shangpin[4]}\n"  # 将商品各字段用逗号连接并添加换行符

# 定义全局商品列表
shangpin_list: List[Product] = []  # 创建空列表存储所有商品信息，使用类型注解

# 定义函数，用于加载商品信息
def load_shangpins():  # 定义加载商品信息的函数
    """加载商品信息"""
    global shangpin_list  # 声明使用全局商品列表变量
    try:  # 使用异常处理确保文件操作安全
        if os.path.exists("shangpins.txt"):  # 检查商品文件是否存在
            with open("shangpins.txt", "r", encoding="utf-8") as file:  # 以UTF-8编码打开商品文件
                for line_num, line in enumerate(file, 1):  # 遍历文件每一行，从1开始编号
                    if not line.strip():  # 检查是否为空行
                        continue  # 跳过空行
                    product = from_csv(line)  # 调用CSV解析函数解析商品信息
                    if product:  # 如果解析成功
                        shangpin_list.append(product)  # 将商品添加到列表中
                    else:  # 解析失败的情况
                        print_warning(f"商品文件第{line_num}行格式错误，已跳过")  # 显示格式错误警告
    except Exception as e:  # 捕获所有其他异常
        print_error(f"加载商品信息失败: {e}")  # 显示加载失败错误

# 定义函数，用于保存商品信息
def save_shangpins():  # 定义保存商品信息的函数
    """保存商品信息"""
    try:  # 使用异常处理确保文件操作安全
        with open("shangpins.txt", "w", encoding="utf-8") as file:  # 以写入模式打开商品文件
            for shangpin in shangpin_list:  # 遍历商品列表中的每个商品
                file.write(to_csv(shangpin))  # 将商品转换为CSV格式并写入文件
    except Exception as e:  # 捕获文件操作异常
        print_error(f"保存商品信息失败: {e}")  # 显示保存失败错误

def validate_product_id(product_id: str) -> bool:  # 定义验证商品编号的函数
    """验证商品编号格式"""
    if not product_id:  # 检查编号是否为空
        print_error("商品编号不能为空")  # 显示编号为空错误
        return False  # 返回验证失败
    if len(product_id) > 20:  # 检查编号长度是否超过20个字符
        print_error("商品编号长度不能超过20个字符")  # 显示长度超限错误
        return False  # 返回验证失败
    return True  # 验证通过，返回成功

def validate_product_name(name: str) -> bool:  # 定义验证商品名称的函数
    """验证商品名称格式"""
    if not name:  # 检查名称是否为空
        print_error("商品名称不能为空")  # 显示名称为空错误
        return False  # 返回验证失败
    if len(name) > 50:  # 检查名称长度是否超过50个字符
        print_error("商品名称长度不能超过50个字符")  # 显示长度超限错误
        return False  # 返回验证失败
    return True  # 验证通过，返回成功

def validate_price(price: int, price_type: str) -> bool:  # 定义验证价格的函数，接收价格和价格类型
    """验证价格"""
    if price < 0:  # 检查价格是否为负数
        print_error(f"{price_type}不能为负数")  # 显示负数错误，使用价格类型参数
        return False  # 返回验证失败
    if price > 999999:  # 检查价格是否超过上限
        print_error(f"{price_type}不能超过999999")  # 显示超限错误
        return False  # 返回验证失败
    return True  # 验证通过，返回成功

def validate_stock(stock: int) -> bool:  # 定义验证库存的函数
    """验证库存"""
    if stock < 0:  # 检查库存是否为负数
        print_error("库存不能为负数")  # 显示负数错误
        return False  # 返回验证失败
    if stock > 999999:  # 检查库存是否超过上限
        print_error("库存不能超过999999")  # 显示超限错误
        return False  # 返回验证失败
    return True  # 验证通过，返回成功

def find_product_by_id(product_id: str) -> Optional[int]:  # 定义根据编号查找商品的函数，返回索引或None
    """根据编号查找商品，返回索引"""
    for i, product in enumerate(shangpin_list):  # 遍历商品列表，获取索引和商品对象
        if product[0] == product_id:  # 比较商品编号（元组第0个元素）
            return i  # 找到匹配商品，返回索引
    return None  # 未找到匹配商品，返回None

def find_product_by_name(name: str) -> Optional[int]:  # 定义根据名称查找商品的函数，返回索引或None
    """根据名称查找商品，返回索引"""
    for i, product in enumerate(shangpin_list):  # 遍历商品列表，获取索引和商品对象
        if product[1] == name:  # 比较商品名称（元组第1个元素）
            return i  # 找到匹配商品，返回索引
    return None  # 未找到匹配商品，返回None

# 定义函数，用于创建商品数据库
def create_database():  # 定义创建商品数据库的函数
    """创建商品数据库"""
    print_header("建立商品数据库")  # 显示数据库创建页面标题
    
    # 获取要添加的商品数量，限制在1-100之间
    num_items = _input_number("请输入要添加的商品数量：", min_val=1, max_val=100)  # 调用数字输入函数，设置最小值1，最大值100
    print_info("请依次输入商品信息：")  # 提示用户开始输入商品信息
    
    # 使用for循环遍历每个要添加的商品
    for i in range(num_items):  # 从0开始循环到num_items-1
        print_separator()  # 打印分隔线，美化界面
        print(f"📦 第 {i + 1} 个商品：")  # 显示当前是第几个商品（i+1是因为i从0开始）
        
        # 输入商品编号的循环，确保编号有效且不重复
        while True:  # 无限循环直到输入有效编号
            bianhao = input("编号: ").strip()  # 获取用户输入的编号并去除空白字符
            if not validate_product_id(bianhao):  # 调用编号验证函数检查格式
                continue  # 验证失败则重新输入
            if find_product_by_id(bianhao) is not None:  # 检查编号是否已存在
                print_error("编号已存在，请重新输入")  # 显示编号重复错误
                continue  # 重新输入编号
            break  # 编号有效且不重复，跳出循环
        
        # 输入商品名称的循环，确保名称有效
        while True:  # 无限循环直到输入有效名称
            mingcheng = input("名称: ").strip()  # 获取用户输入的名称并去除空白字符
            if validate_product_name(mingcheng):  # 调用名称验证函数检查格式
                break  # 验证通过则跳出循环
        
        # 输入进价，使用数字输入函数确保输入有效
        jinjia = _input_number("进价: ", min_val=0, max_val=999999)  # 调用数字输入函数，设置最小值0，最大值999999
        
        # 输入售价的循环，需要检查是否低于进价
        while True:  # 无限循环直到输入合理的售价
            shoujia = _input_number("售价: ", min_val=0, max_val=999999)  # 调用数字输入函数获取售价
            if shoujia < jinjia:  # 检查售价是否低于进价
                print_warning("售价低于进价，可能会亏损，确定要继续吗？(y/n)")  # 显示亏损警告
                if input().strip().lower() == 'y':  # 获取用户确认，转换为小写进行比较
                    break  # 用户确认则跳出循环
            else:  # 售价不低于进价的情况
                break  # 直接跳出循环
        
        # 输入库存，使用数字输入函数确保输入有效
        kucun = _input_number("库存: ", min_val=0, max_val=999999)  # 调用数字输入函数，设置最小值0，最大值999999
        
        # 将商品信息添加到商品列表中
        shangpin_list.append((bianhao, mingcheng, jinjia, shoujia, kucun))  # 创建商品元组并添加到全局商品列表
        print_success(f"商品 '{mingcheng}' 添加成功")  # 显示单个商品添加成功信息
    
    save_shangpins()  # 调用保存函数将所有商品信息保存到文件
    print_success(f"成功添加 {num_items} 个商品到数据库！")  # 显示批量添加完成信息

def display_product(product: Product, index: int = None):  # 定义显示单个商品信息的函数，index参数可选
    """显示单个商品信息"""
    # 计算利润率：(售价-进价)/进价*100，如果进价为0则利润率为0
    profit_margin = ((product[3] - product[2]) / product[2] * 100) if product[2] > 0 else 0  # 使用三元运算符避免除零错误
    # 根据库存数量判断库存状态：>10为充足，>0为偏低，=0为缺货
    stock_status = "充足" if product[4] > 10 else "偏低" if product[4] > 0 else "缺货"  # 使用嵌套三元运算符判断库存状态
    
    if index is not None:
        print(f"�� 商品 #{index + 1}")
    print(f"编号: {product[0]}")
    print(f"名称: {product[1]}")
    print(f"进价: ¥{product[2]}")
    print(f"售价: ¥{product[3]}")
    print(f"库存: {product[4]} 件 ({stock_status})")
    print(f"利润率: {profit_margin:.1f}%")

# 定义函数，用于显示全部商品信息
def display_all():  # 定义显示所有商品信息的函数
    """显示全部商品信息"""
    print_header("商品库存一览")  # 显示商品库存页面标题
    
    # 检查商品列表是否为空
    if not shangpin_list:  # 如果商品列表为空（长度为0）
        print_info("暂无商品信息")  # 显示无商品提示信息
        return  # 直接返回，结束函数执行
    
    # 计算统计数据
    total_value = sum(p[2] * p[4] for p in shangpin_list)  # 计算总库存价值：每个商品的进价*库存数量之和
    total_items = len(shangpin_list)  # 获取商品种类数量
    total_stock = sum(p[4] for p in shangpin_list)  # 计算总库存数量：所有商品库存之和
    
    # 显示统计信息
    print(f"📊 统计信息：")  # 显示统计信息标题
    print(f"   商品种类: {total_items} 种")  # 显示商品种类数量
    print(f"   总库存量: {total_stock} 件")  # 显示总库存数量
    print(f"   库存总价值: ¥{total_value}")  # 显示库存总价值
    print_separator()  # 打印分隔线
    
    # 遍历并显示每个商品的详细信息
    for i, product in enumerate(shangpin_list):  # 使用enumerate获取索引和商品对象
        display_product(product, i)  # 调用显示单个商品函数，传入商品对象和索引
        print_separator()  # 在每个商品信息后打印分隔线

# 定义函数，用于进货
def restock():  # 定义进货功能函数
    """进货功能"""
    print_header("商品进货")  # 显示进货页面标题
    
    # 获取进货商品名称并验证
    mingcheng = input("请输入进货商品名称: ").strip()  # 获取用户输入的商品名称并去除空白字符
    if not validate_product_name(mingcheng):  # 调用名称验证函数检查格式
        return  # 验证失败则直接返回，结束函数执行
    
    # 查找商品是否已存在
    index = find_product_by_name(mingcheng)  # 根据商品名称查找商品在列表中的索引
    
    # 判断商品是否存在，分两种情况处理
    if index is not None:  # 如果找到了商品（索引不为None）
        # 商品已存在，增加库存的处理流程
        product = shangpin_list[index]  # 从商品列表中获取找到的商品对象
        print_info(f"找到商品: {product[1]}")  # 显示找到的商品名称
        display_product(product)  # 调用函数显示商品详细信息
        
        # 获取要增加的库存数量
        kucun = _input_number("请输入增加的库存量: ", min_val=1, max_val=999999)  # 调用数字输入函数获取库存增量
        new_stock = product[4] + kucun  # 计算新的库存总量：原库存+增加量
        
        # 检查新库存是否超过系统限制
        if new_stock > 999999:  # 如果新库存超过最大限制
            print_error("库存总量不能超过999999")  # 显示错误信息
            return  # 直接返回，结束函数执行
        
        # 更新商品信息并保存
        shangpin_list[index] = (product[0], product[1], product[2], product[3], new_stock)  # 创建新的商品元组替换原商品
        save_shangpins()  # 调用保存函数将更新后的商品信息保存到文件
        print_success(f"进货成功！{product[1]} 库存增加 {kucun} 件，当前库存: {new_stock} 件")  # 显示进货成功信息
    else:  # 如果没有找到商品（索引为None）
        # 新商品，需要完整信息的处理流程
        print_info("该商品不存在，请输入完整商品信息")  # 提示用户输入新商品信息
        print_separator()  # 打印分隔线美化界面
        
        # 输入新商品编号的循环，确保编号有效且不重复
        while True:  # 无限循环直到输入有效编号
            bianhao = input("编号: ").strip()  # 获取用户输入的编号并去除空白字符
            if not validate_product_id(bianhao):  # 调用编号验证函数检查格式
                continue  # 验证失败则重新输入
            if find_product_by_id(bianhao) is not None:  # 检查编号是否已存在
                print_error("编号已存在，请重新输入")  # 显示编号重复错误
                continue  # 重新输入编号
            break  # 编号有效且不重复，跳出循环
        
        # 输入新商品的价格信息
        jinjia = _input_number("进价: ", min_val=0, max_val=999999)  # 调用数字输入函数获取进价
        
        # 输入售价的循环，需要检查是否低于进价
        while True:  # 无限循环直到输入合理的售价
            shoujia = _input_number("售价: ", min_val=0, max_val=999999)  # 调用数字输入函数获取售价
            if shoujia < jinjia:  # 检查售价是否低于进价
                print_warning("售价低于进价，可能会亏损，确定要继续吗？(y/n)")  # 显示亏损警告
                if input().strip().lower() == 'y':  # 获取用户确认，转换为小写进行比较
                    break  # 用户确认则跳出循环
            else:  # 售价不低于进价的情况
                break  # 直接跳出循环
        
        # 输入新商品的库存数量
        kucun = _input_number("库存: ", min_val=1, max_val=999999)  # 调用数字输入函数获取库存数量
        
        # 将新商品添加到商品列表并保存
        shangpin_list.append((bianhao, mingcheng, jinjia, shoujia, kucun))  # 创建新商品元组并添加到商品列表
        save_shangpins()  # 调用保存函数将新商品信息保存到文件
        print_success(f"新商品 '{mingcheng}' 添加成功！")  # 显示新商品添加成功信息

# 定义函数，用于退货
def return_stock():
    """退货功能"""
    print_header("商品退货")
    
    if not shangpin_list:
        print_info("暂无商品可退货")
        return
    
    tui_name = input("请输入退货商品名称: ").strip()
    if not tui_name:
        print_error("商品名称不能为空")
        return
    
    index = find_product_by_name(tui_name)
    
    if index is not None:
        product = shangpin_list[index]
        print_info(f"找到商品:")
        display_product(product)
        
        print_warning("确定要删除该商品吗？此操作不可撤销！(y/n)")
        if input().strip().lower() == 'y':
            del shangpin_list[index]
            save_shangpins()
            print_success("退货成功")
        else:
            print_info("已取消退货操作")
    else:
        print_error("未找到该商品")

# 定义函数，用于商品销售
def sell():
    """商品销售"""
    print_header("商品销售")
    
    if not shangpin_list:
        print_info("暂无商品可销售")
        return
    
    sell_bianhao = input("请输入购买商品的编号: ").strip()
    if not sell_bianhao:
        print_error("商品编号不能为空")
        return
    
    index = find_product_by_id(sell_bianhao)
    
    if index is None:
        print_error("未找到该商品")
        return
    
    product = shangpin_list[index]
    print_info(f"商品信息:")
    display_product(product)
    
    if product[4] == 0:
        print_error("该商品库存为0，无法销售")
        return
    
    max_quantity = product[4]
    n = _input_number(f"请输入购买数量 (最多 {max_quantity} 件): ", min_val=1, max_val=max_quantity)
    
    # 计算金额
    unit_price = product[3]
    total_amount = n * unit_price
    
    print_separator()
    print(f"💰 销售详情:")
    print(f"   商品: {product[1]}")
    print(f"   单价: ¥{unit_price}")
    print(f"   数量: {n} 件")
    print(f"   应收金额: ¥{total_amount}")
    print_separator()
    
    q = _input_number("实际收款: ", min_val=0)
    
    if q < total_amount:
        print_error(f"收款不足，还差 ¥{total_amount - q}")
        return
    
    # 更新库存
    new_stock = product[4] - n
    shangpin_list[index] = (product[0], product[1], product[2], product[3], new_stock)
    save_shangpins()
    
    # 显示交易结果
    change = q - total_amount
    print_success("交易成功！")
    print(f"💵 找零: ¥{change}")
    print(f"📦 剩余库存: {new_stock} 件")
    
    # 记录销售日志
    log_sale(product[1], n, total_amount)

def log_sale(product_name: str, quantity: int, amount: int):
    """记录销售日志"""
    try:
        timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        with open("sales_log.txt", "a", encoding="utf-8") as file:
            file.write(f"{timestamp},{product_name},{quantity},{amount}\n")
    except Exception as e:
        print_warning(f"销售日志记录失败: {e}")

# 定义函数，用于商品查询
def query():
    """商品查询"""
    print_header("商品查询")
    
    if not shangpin_list:
        print_info("暂无商品信息")
        return
    
    c = _input_number("请选择查询方式:\n1. 编号查询\n2. 名称查询\n3. 价格范围查询\n4. 库存预警查询\n请选择: ", min_val=1, max_val=4)
    
    if c == 1:
        # 编号查询
        cha_bianhao = input("请输入商品编号: ").strip()
        if not cha_bianhao:
            print_error("商品编号不能为空")
            return
        
        index = find_product_by_id(cha_bianhao)
        if index is not None:
            print_separator()
            display_product(shangpin_list[index])
        else:
            print_error("未找到该商品")
    
    elif c == 2:
        # 名称查询
        cha_mingcheng = input("请输入商品名称: ").strip()
        if not cha_mingcheng:
            print_error("商品名称不能为空")
            return
        
        found = False
        for product in shangpin_list:
            if cha_mingcheng.lower() in product[1].lower():
                if not found:
                    print_separator()
                    found = True
                display_product(product)
                print_separator()
        
        if not found:
            print_error("未找到匹配的商品")
    
    elif c == 3:
        # 价格范围查询
        min_price = _input_number("请输入最低价格: ", min_val=0)
        max_price = _input_number("请输入最高价格: ", min_val=min_price)
        
        found = False
        for product in shangpin_list:
            if min_price <= product[3] <= max_price:
                if not found:
                    print_separator()
                    found = True
                display_product(product)
                print_separator()
        
        if not found:
            print_error("该价格范围内没有商品")
    
    elif c == 4:
        # 库存预警查询
        threshold = _input_number("请输入库存预警阈值: ", min_val=0, max_val=100)
        
        found = False
        for product in shangpin_list:
            if product[4] <= threshold:
                if not found:
                    print_info(f"库存低于 {threshold} 件的商品:")
                    print_separator()
                    found = True
                display_product(product)
                print_separator()
        
        if not found:
            print_success("所有商品库存充足")

# 定义函数，用于商品排序
def sort_items():
    """商品排序"""
    print_header("商品排序")
    
    if not shangpin_list:
        print_info("暂无商品可排序")
        return
    
    x = _input_number("请选择排序方式:\n1. 按商品编号排序\n2. 按商品价格排序\n3. 按库存数量排序\n4. 按利润率排序\n请选择: ", min_val=1, max_val=4)
    
    order = _input_number("请选择排序顺序:\n1. 升序\n2. 降序\n请选择: ", min_val=1, max_val=2)
    reverse = (order == 2)
    
    if x == 1:
        shangpin_list.sort(key=lambda sp: sp[0], reverse=reverse)
        print_success("按商品编号排序完成")
    elif x == 2:
        shangpin_list.sort(key=lambda sp: sp[3], reverse=reverse)
        print_success("按商品价格排序完成")
    elif x == 3:
        shangpin_list.sort(key=lambda sp: sp[4], reverse=reverse)
        print_success("按库存数量排序完成")
    elif x == 4:
        shangpin_list.sort(key=lambda sp: (sp[3] - sp[2]) / sp[2] if sp[2] > 0 else 0, reverse=reverse)
        print_success("按利润率排序完成")
    
    save_shangpins()

def show_statistics():
    """显示统计信息"""
    print_header("数据统计")
    
    if not shangpin_list:
        print_info("暂无数据可统计")
        return
    
    total_items = len(shangpin_list)
    total_stock = sum(p[4] for p in shangpin_list)
    total_cost_value = sum(p[2] * p[4] for p in shangpin_list)
    total_sell_value = sum(p[3] * p[4] for p in shangpin_list)
    potential_profit = total_sell_value - total_cost_value
    
    # 库存状态统计
    out_of_stock = sum(1 for p in shangpin_list if p[4] == 0)
    low_stock = sum(1 for p in shangpin_list if 0 < p[4] <= 10)
    normal_stock = total_items - out_of_stock - low_stock
    
    # 价格统计
    prices = [p[3] for p in shangpin_list]
    avg_price = sum(prices) / len(prices)
    max_price = max(prices)
    min_price = min(prices)
    
    print(f"📊 商品统计:")
    print(f"   商品种类: {total_items} 种")
    print(f"   总库存量: {total_stock} 件")
    print(f"   库存成本价值: ¥{total_cost_value}")
    print(f"   库存销售价值: ¥{total_sell_value}")
    print(f"   潜在利润: ¥{potential_profit}")
    print()
    print(f"📦 库存状态:")
    print(f"   正常库存: {normal_stock} 种")
    print(f"   库存偏低: {low_stock} 种")
    print(f"   缺货商品: {out_of_stock} 种")
    print()
    print(f"💰 价格分析:")
    print(f"   平均售价: ¥{avg_price:.2f}")
    print(f"   最高售价: ¥{max_price}")
    print(f"   最低售价: ¥{min_price}")

def backup_data():
    """备份数据"""
    print_header("数据备份")
    
    try:
        timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
        
        # 备份商品数据
        if os.path.exists("shangpins.txt"):
            backup_file = f"shangpins_backup_{timestamp}.txt"
            with open("shangpins.txt", "r", encoding="utf-8") as src:
                with open(backup_file, "w", encoding="utf-8") as dst:
                    dst.write(src.read())
            print_success(f"商品数据已备份到: {backup_file}")
        
        # 备份管理员数据
        if os.path.exists("admins.txt"):
            backup_file = f"admins_backup_{timestamp}.txt"
            with open("admins.txt", "r", encoding="utf-8") as src:
                with open(backup_file, "w", encoding="utf-8") as dst:
                    dst.write(src.read())
            print_success(f"管理员数据已备份到: {backup_file}")
        
        print_success("数据备份完成！")
    
    except Exception as e:
        print_error(f"数据备份失败: {e}")

# 定义函数，用于输入一个有效的数字
def _input_number(prompt: str, min_val: int = None, max_val: int = None) -> int:  # 定义输入数字的函数，支持范围限制
    """输入有效数字，支持范围限制"""
    while True:  # 无限循环直到输入有效数字
        try:  # 使用异常处理捕获输入错误
            value = int(input(prompt).strip())  # 获取用户输入并转换为整数
            if min_val is not None and value < min_val:  # 检查是否小于最小值
                print_error(f"输入值不能小于 {min_val}")  # 显示小于最小值错误
                continue  # 重新输入
            if max_val is not None and value > max_val:  # 检查是否大于最大值
                print_error(f"输入值不能大于 {max_val}")  # 显示大于最大值错误
                continue  # 重新输入
            return value  # 输入有效，返回数值
        except ValueError:  # 捕获类型转换异常
            print_error("请输入一个有效的数字")  # 显示输入格式错误

def show_main_menu():  # 定义显示主菜单的函数
    """显示主菜单"""
    print("\n" + "🏪 超市管理系统".center(60, "="))  # 居中显示系统标题，用等号填充到60字符
    print("1. 👤 注册管理员")  # 显示注册选项
    print("2. 🔐 管理员登录")  # 显示登录选项
    print("3. 🚪 退出系统")  # 显示退出选项
    print("=" * 60)  # 打印60个等号作为菜单底边框

def show_admin_menu():  # 定义显示管理员菜单的函数
    """显示管理员菜单"""
    print("\n" + "📋 管理员控制面板".center(60, "*"))  # 居中显示管理员面板标题，用星号填充
    print("1. 🏗️  建立数据库")  # 显示建立数据库选项
    print("2. 📦 显示全部商品信息")  # 显示查看商品选项
    print("3. 📥 进货")  # 显示进货选项
    print("4. 📤 退货")  # 显示退货选项
    print("5. 💰 商品销售")  # 显示销售选项
    print("6. 🔍 商品查询")  # 显示查询选项
    print("7. 📊 商品排序")  # 显示排序选项
    print("8. 📈 数据统计")  # 显示统计选项
    print("9. 💾 数据备份")  # 显示备份选项
    print("0. 🚪 退出系统")  # 显示退出选项
    print("*" * 60)  # 打印60个星号作为菜单底边框

# 主函数
def main():  # 定义程序主函数
    """主函数"""
    # 加载数据
    load_admins()  # 加载管理员信息
    load_shangpins()  # 加载商品信息
    
    print("🎉 欢迎使用超市管理系统 🎉".center(60, "="))  # 居中显示欢迎信息
    print("系统初始化完成...")  # 显示初始化完成信息
    
    # 如果没有管理员，提示创建
    if not admins:  # 检查是否存在管理员账户
        print_warning("系统中暂无管理员，请先注册管理员账户")  # 提示注册管理员
    
    while True:  # 主程序循环
        show_main_menu()  # 显示主菜单
        choice = input("请选择操作: ").strip()  # 获取用户选择
        
        if choice == '1':  # 用户选择注册管理员
            register()  # 调用注册函数
        elif choice == '2':  # 用户选择管理员登录
            if login():  # 调用登录函数，如果登录成功
                while True:  # 管理员操作循环
                    show_admin_menu()  # 显示管理员菜单
                    admin_choice = input("请选择操作: ").strip()  # 获取管理员选择
                    
                    if admin_choice == '1':  # 建立数据库
                        create_database()  # 调用建立数据库函数
                    elif admin_choice == '2':  # 显示全部商品
                        display_all()  # 调用显示所有商品函数
                    elif admin_choice == '3':  # 进货
                        restock()  # 调用进货函数
                    elif admin_choice == '4':  # 退货
                        return_stock()  # 调用退货函数
                    elif admin_choice == '5':  # 商品销售
                        sell()  # 调用销售函数
                    elif admin_choice == '6':  # 商品查询
                        query()  # 调用查询函数
                    elif admin_choice == '7':  # 商品排序
                        sort_items()  # 调用排序函数
                    elif admin_choice == '8':  # 数据统计
                        show_statistics()  # 调用统计函数
                    elif admin_choice == '9':  # 数据备份
                        backup_data()  # 调用备份函数
                    elif admin_choice == '0':  # 退出系统
                        print_success("感谢使用超市管理系统，再见！")  # 显示退出信息
                        return  # 退出程序
                    else:  # 无效选择
                        print_error("输入错误，请重新选择")  # 显示错误信息
                    
                    input("\n按回车键继续...")  # 等待用户按键继续
        elif choice == '3':  # 用户选择退出系统
            print_success("感谢使用超市管理系统，再见！")  # 显示退出信息
            break  # 跳出主循环
        else:  # 无效选择
            print_error("输入错误，请重新选择")  # 显示错误信息

if __name__ == "__main__":  # 检查是否为主程序运行
    try:  # 使用异常处理确保程序稳定
        main()  # 调用主函数
    except KeyboardInterrupt:  # 捕获键盘中断异常（Ctrl+C）
        print("\n\n👋 程序被用户中断，再见！")  # 显示中断信息
    except Exception as e:  # 捕获所有其他异常
        print_error(f"程序运行出错: {e}")  # 显示错误信息
        input("按回车键退出...")  # 等待用户按键后退出
